package cn.com.lms.business.livecourse.service;

import cn.com.lms.business.livecourse.constant.AliRtcConstants;
import cn.com.lms.business.livecourse.persistence.entity.rtc.AuthInfo;
import cn.com.lms.business.livecourse.persistence.entity.rtc.Turn;
import cn.com.lms.business.livecourse.util.AliSignUtil;
import cn.com.lms.business.livecourse.util.HttpClientUtil;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.sun.net.httpserver.HttpExchange;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * AliRtcService
 *
 * @author barry
 * @date 2020/3/24
 **/
@Service
public class AliRtcService {

    /**
     * 获取Rtc登录授权凭证
     * @param channelID  频道名（房间名）
     * @param user      用户名
     * @return
     */
    public AuthInfo v1Login(String channelID, String user) {
        if (channelID == "" || user == "") {
            return null;
        }

        String userID;
        String nonce;
        long timestamp;
        String token;
        try {
            userID = createUserID(channelID, user);

            // Warning: nonce support the AppKey generated token.
            // the Nonce should be prefix with 'AK-' otherwise the joining verification will failed.
            // eg. nonce: "AK-0464002093ce3dd010cb05356c8b1d0f".
            nonce = String.format("AK-%s", UUID.randomUUID().toString());

            // Warning: timestamp is the token expiration time.
            // User can custom defined the expire time of token.
            // eg, Expires in two days. timestamp: 1559890860.
            Calendar nowTime = Calendar.getInstance();
            nowTime.add(Calendar.HOUR_OF_DAY, 48);
            timestamp = nowTime.getTimeInMillis() / 1000;

            token = createToken(AliRtcConstants.APP_ID, AliRtcConstants.APP_KEY, channelID, userID, nonce, timestamp);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        String username = String.format("%s?appid=%s&channel=%s&nonce=%s&timestamp=%d",
                userID, AliRtcConstants.APP_ID, channelID, nonce, timestamp);

        System.out.printf("Login: appID=%s, appKey=%s, channelID=%s, userID=%s, nonce=%s, "+
                        "timestamp=%d, user=%s, userName=%s, token=%s\n",
                AliRtcConstants.APP_ID, AliRtcConstants.APP_KEY, channelID, userID, nonce, timestamp, user, username, token);

//        JSONObject response = new JSONObject()
//                .put("code", 0)
//                .put("data", new JSONObject()
//                        .put("appid", AliRtcConstants.APP_ID)
//                        .put("userid", userID)
//                        .put("gslb", new JSONArray().put(AliRtcConstants.GSLB))
//                        .put("token", token)
//                        .put("nonce", nonce)
//                        .put("timestamp", timestamp)
//                        .put("turn", new JSONObject()
//                                .put("username", username)
//                                .put("password", token)
//                        ));
//        return response.toString();
        AuthInfo authInfo = new AuthInfo();
        authInfo.setAppid(AliRtcConstants.APP_ID);
        authInfo.setUserid(userID);
        String[] gslbs = new String[]{AliRtcConstants.GSLB};
        authInfo.setGslb(gslbs);
        authInfo.setToken(token);
        authInfo.setNonce(nonce);
        authInfo.setTimestamp(timestamp);
        Turn turn = new Turn();
        turn.setUsername(username);
        turn.setPassword(token);
        authInfo.setTurn(turn);
        authInfo.setChannel(channelID);

        return authInfo;
    }

    public static String createToken(
            String appId, String appKey, String channelId, String userId,
            String nonce, Long timestamp
    ) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(appId.getBytes());
        digest.update(appKey.getBytes());
        digest.update(channelId.getBytes());
        digest.update(userId.getBytes());
        digest.update(nonce.getBytes());
        digest.update(Long.toString(timestamp).getBytes());

        String token = DatatypeConverter.printHexBinary(digest.digest()).toLowerCase();
        return token;
    }

    public static String createUserID(String channelID, String user) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(channelID.getBytes());
        digest.update("/".getBytes());
        digest.update(user.getBytes());

        String uid = DatatypeConverter.printHexBinary(digest.digest()).toLowerCase();
        return uid.substring(0, 16);
    }

    private void httpWrite(HttpExchange he, int code, String response) throws IOException {
        OutputStream os = he.getResponseBody();
        he.sendResponseHeaders(code, response.length());
        os.write(response.getBytes());
        os.close();
    }


    /**
     * 开始Rtc直播
     * @param courseId      直播课程id
     * @param streamName    直播流名称
     * @param pushStreamUrl 推流地址
     * @return 结果结HashMap  存在字段 success和message
     */
    public HashMap<String, Object> startRtcLive(String courseId, String streamName, String pushStreamUrl) {
        HashMap<String, Object> actionResult = new HashMap<>();
        actionResult.put("success", false);
        actionResult.put("message", "");
        actionResult.put("requestId", "");

        // 私有参数
        Map<String, String> privateParams = new HashMap<String, String>();
        privateParams.put("Action", AliRtcConstants.ACTION_START_LIVE);
        privateParams.put("AppId", AliRtcConstants.APP_ID);
        privateParams.put("ChannelId", courseId);
        privateParams.put("LayoutIds.1", "1");
        privateParams.put("MediaEncode", "30");     // 27 720p; 30 1080p
        privateParams.put("StreamURL", pushStreamUrl);
        privateParams.put("TaskId", streamName);
        // 获取已签名的请求url
        String requestUrl = AliSignUtil.signRequestUrl(AliRtcConstants.SERVICE_DOMAIN, "GET", privateParams);
        String response = "";
        try {
            response = HttpClientUtil.get(requestUrl);
        } catch (IOException e) {
            e.printStackTrace();
            actionResult.put("message", e.getMessage());
            return actionResult;
        }
        System.out.println("response = " + response);
        if (StringUtils.isEmpty(response)) {
            actionResult.put("message", "开始直播--请求返回信息为空");
            return actionResult;
        }
        JsonParser parser = new JsonParser();
        JsonObject jsonObject  = parser.parse(response).getAsJsonObject();
        if (null == jsonObject || !jsonObject.has("RequestId")) {
            actionResult.put("message", "开始直播--请求返回信息解析异常");
            return actionResult;
        }
        String requestId = jsonObject.get("RequestId").getAsString();
        actionResult.put("requestId", requestId);
        if (jsonObject.has("Message")) {
            actionResult.put("message", "开始直播--" + jsonObject.get("Message").getAsString());
            return actionResult;
        }

        actionResult.put("success", true);
        return actionResult;
    }

    /**
     * 停止Rtc直播
     * @param streamName    直播流名称
     * @return 结果结HashMap  存在字段 success和message
     */
    public HashMap<String, Object> stopRtcLive(String streamName) {
        HashMap<String, Object> actionResult = new HashMap<>();
        actionResult.put("success", false);
        actionResult.put("message", "");
        actionResult.put("requestId", "");

        // 私有参数
        Map<String, String> privateParams = new HashMap<String, String>();
        privateParams.put("Action", AliRtcConstants.ACTION_STOP_LIVE);
        privateParams.put("AppId", AliRtcConstants.APP_ID);
        privateParams.put("TaskId", streamName);
        // 获取已签名的请求url
        String requestUrl = AliSignUtil.signRequestUrl(AliRtcConstants.SERVICE_DOMAIN, "GET", privateParams);
        String response = "";
        try {
            response = HttpClientUtil.get(requestUrl);
        } catch (IOException e) {
            e.printStackTrace();
            actionResult.put("message", e.getMessage());
            return actionResult;
        }
        System.out.println("response = " + response);
        if (StringUtils.isEmpty(response)) {
            actionResult.put("message", "停止直播--请求返回信息为空");
            return actionResult;
        }
        JsonParser parser = new JsonParser();
        JsonObject jsonObject  = parser.parse(response).getAsJsonObject();
        if (null == jsonObject || !jsonObject.has("RequestId")) {
            actionResult.put("message", "停止直播--请求返回信息解析异常");
            return actionResult;
        }
        String requestId = jsonObject.get("RequestId").getAsString();
        actionResult.put("requestId", requestId);
        if (jsonObject.has("Message")) {
            actionResult.put("message", "停止直播--" + jsonObject.get("Message").getAsString());
            return actionResult;
        }

        actionResult.put("success", true);
        return actionResult;
    }



    public HashMap<String, Object> GetMPUTaskStatus(String streamName) {
        HashMap<String, Object> actionResult = new HashMap<>();
        actionResult.put("success", false);
        actionResult.put("message", "");
        actionResult.put("requestId", "");
        actionResult.put("status", -1);

        // 私有参数
        Map<String, String> privateParams = new HashMap<String, String>();
        privateParams.put("Action", "GetMPUTaskStatus");
        privateParams.put("AppId", AliRtcConstants.APP_ID);
        privateParams.put("TaskId", streamName);
        // 获取已签名的请求url
        String requestUrl = AliSignUtil.signRequestUrl(AliRtcConstants.SERVICE_DOMAIN, "GET", privateParams);
        String response = "";
        try {
            response = HttpClientUtil.get(requestUrl);
        } catch (IOException e) {
            e.printStackTrace();
            actionResult.put("message", e.getMessage());
            return actionResult;
        }
        System.out.println("response = " + response);
        if (StringUtils.isEmpty(response)) {
            actionResult.put("message", "开始直播--请求返回信息为空");
            return actionResult;
        }
        JsonParser parser = new JsonParser();
        JsonObject jsonObject  = parser.parse(response).getAsJsonObject();
        if (null == jsonObject || !jsonObject.has("RequestId")) {
            actionResult.put("message", "直播状态--请求返回信息解析异常");
            return actionResult;
        }
        String requestId = jsonObject.get("RequestId").getAsString();
        actionResult.put("requestId", requestId);
        if (jsonObject.has("Message")) {
            actionResult.put("message", "直播状态--" + jsonObject.get("Message").getAsString());
            return actionResult;
        }
        if (jsonObject.has("Status")) {
            actionResult.put("message", "直播状态--" + jsonObject.get("Status").getAsInt());
            actionResult.put("status", jsonObject.get("Status").getAsInt());
            return actionResult;
        }

        actionResult.put("success", true);
        return actionResult;
    }
}
